grammar Bling;

options {
 output = AST;
 ASTLabelType=CommonTree;
 k=2;
}

tokens {
	TAG_ATTRIBUTE;
	SNIPPET;
	TAG_OPENING;
	TAG_CLOSING;
	TAG_SELF_CLOSING;
	TEXT;
	ROOT;
}

@header {
  package org.bling.language;
}

@lexer::header {
  package org.bling.language;
}

/* ############################## L E X E R ############################ */

LINEEND :  ('\r'|'\n') {$channel=HIDDEN;};
          
XML_COMMENT : COMMENT_OPEN ( options {greedy=false;} : . )* COMMENT_CLOSE {$channel=HIDDEN;};
WHITESPACE :  (' '|'\t'|'\u000C') {$channel=HIDDEN;};

CODE_SNIPPET : COMMAND_OPEN! ( options {greedy=false;} : . )* COMMAND_CLOSE!;

WORD : ~(TAG_OPEN|TAG_CLOSE|'\n'|'\r'|' '|'\t'|'\u000C'|'='|'"')+;

STRING_LITERAL 	: '"'! ~('"'|'\r'|'\n')* '"'!;

TAG_OPEN        : '<';
TAG_CLOSE       : '>';
TAG_SELF_CLOSE  : '/>';
COMMENT_OPEN    : '<!--';
COMMENT_CLOSE   : '-->';
COMMAND_OPEN    : '<%';
COMMAND_CLOSE   : '%>';
CLOSING_TAG     : '</';


/* ############################## P A R S E R ############################ */

bling 	: statement* -> ^(ROOT statement*);

statement : tag | text;

text	: WORD+ -> ^(TEXT WORD+);

tag	: opening_tag |
          closing_tag |
          code_snippet;

opening_tag : TAG_OPEN WORD attributes? (
                 TAG_CLOSE -> ^(TAG_OPENING WORD attributes?) |
                 TAG_SELF_CLOSE -> ^(TAG_SELF_CLOSING WORD attributes?)
                 ); // Opening Tag <open>

closing_tag : CLOSING_TAG WORD TAG_CLOSE -> ^(TAG_CLOSING WORD); // Closing Tag </close>

code_snippet : CODE_SNIPPET -> ^(SNIPPET CODE_SNIPPET);

attributes : attribute+;
	
attribute : WORD '=' STRING_LITERAL -> ^(TAG_ATTRIBUTE WORD STRING_LITERAL);
